import json
import pickle
from collections import defaultdict

import pandas as pd


class Node:
    base = 'Node'
    buttom = []
    above = []
    arg = {}
    ret = {}

    def __init__(self, name):
        buttom = []
        above = []
        arg = {}
        ret = {}
        self.name = name

    def __eq__(self, obj):
        try:
            result = (obj.base == self.base)
        except:
            return False
        return True

    def excute(self):
        pass

    def add_buttom(self, node):
        self.buttom.append(node)

    def add_above(self, node):
        self.above.append(node)


class Model(Node):
    buttom = []
    above = []
    arg = {'data': None}
    ret = {'return': None}

    def __init__(self, name):
        super().__init__(name)

    def excute(self):
        print('run:', self.name)
        return self


class Load(Node):
    def __init__(self, name):
        super().__init__(name)
        buttom = []
        above = []
        arg = {'path': None, "type": None}
        ret = {'return': None}

    def excute(self):
        print(self.excute.__defaults__)  # 使用__code__#总参数个数
        print(self.excute.__code__.co_argcount)  # 总参数名
        print(self.excute.__code__.co_varnames)
        print('run:', self.name)
        return self


class Out(Node):
    buttom = []
    above = []
    arg = {'data': None}
    ret = {'return': None}

    def __init__(self, name):
        super().__init__(name)

    def excute(self):
        print('run:', self.name)
        return self


class Graph:
    def __init__(self, vertices):
        self.graph = defaultdict(list)
        self.V = vertices

    def addEdge(self, u, v):
        self.graph[u].append(v)

    def topologicalSortUtil(self, v, visited, stack):

        visited[v] = True

        for i in self.graph[v]:
            if visited[i] == False:
                self.topologicalSortUtil(i, visited, stack)

        stack.insert(0, v)

    def topologicalSort(self):
        visited = [False] * self.V
        stack = []

        for i in range(self.V):
            if visited[i] == False:
                self.topologicalSortUtil(i, visited, stack)

        return stack


class ModelBuilder:
    def __init__(self):
        self.rule = None
        self.root = None
        self.struct = None
        self.graph = None

    def loads(self, jsond):
        self.rule = json.loads(jsond)
        self.root = self.rule['struct'][0]
        self.struct = self.rule['struct']
        for index, node in enumerate(self.struct):
            node['index'] = index
        # exit()
        self.graph = Graph(len(self.struct))

    def find_node(self, node_name):
        rnode = None
        for index, node in enumerate(self.struct):
            if self.struct[index]['name'] == node_name:
                rnode = node
                return rnode
        if rnode == None:
            raise Exception("未知的节点%s" % node_name)

    def find_index(self, node_index):
        for index, node in enumerate(self.struct):
            if self.struct[index]['index'] == node_index:
                return node

    def build(self):
        if self.rule != None:
            check = (self.root['name'] == 'root')
            node_name = {}
            for node in self.struct:
                node_name[node['name']] = -1
            for node in self.struct:
                node_name[node['name']] += 1
            check &= (sum([node_name[x] for x in node_name]) == 0)
            if not check:
                raise Exception("结构语法错误:节点命名重复", node_name)
            else:
                self._build(self.root)
            build_result = []
            for node in self.struct:
                if len(node['buttom']) == 0:
                    build_result.append(node)
            return self.struct
        else:
            raise Exception('没有加载词法树')

    def _build(self, node):
        if node == None:
            print(node)
        node['compiled'] = False
        node['compile'] = globals()[node['type']]
        self.graph.addEdge(node['index'], node['index'])
        for child_name in node['buttom']:
            child = self.find_node(child_name)
            self.graph.addEdge(node['index'], child['index'])
            self._build(child)

    def compile(self):
        self._compile(self.root, None)
        return self.struct

    def _compile(self, node, father):

        if node['compiled'] == False:
            node['compile'] = node['compile'](node['name'])
            node['compile'].arg = node['args']
        node['compiled'] = True
        for child_name in node['buttom']:
            child = self.find_node(child_name)
            self._compile(child, node)

    def exec(self):
        exec_list=self.graph.topologicalSort()
        for node_index in exec_list:
            node=self.find_index(node_index)
            node['compile'].excute()
# 实现一个简单的流程编译器 昨天写完了不管
if __name__ == '__main__':
    # with open("./quant_tactics/singal_two_rule.json") as file:
    with open("./quant_tactics/base_rule.json") as file:
        content = file.read()
        builder = ModelBuilder()
        builder.loads(content)
        builder.build()
        builder.compile()
        builder.exec()
